/* <pre>
 * Copyright (c) The Loose Coupling Team.
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *
 *      http://www.apache.org/licenses/LICENSE-2.0 
 *
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 *</pre>
 */

package org.lc.eic.messageconstruct.requestreply.jaxb.impl;

import java.io.InputStream;
import java.io.OutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.lc.eic.messageconstruct.jaxb.content.ContentMapper;
import org.lc.eic.messgeconstruct.requestreply.Reply;
import org.lc.eic.messgeconstruct.requestreply.ReplySerializer;
import org.lc.eic.messgeconstruct.requestreply.exception.DeserializeException;
import org.lc.eic.messgeconstruct.requestreply.exception.SerializeException;
import org.lc.reply._1_0.ObjectFactory;



/**
 *  TODO: Add type comment here!!
 *	@author <a href="mailto:p.lycke@googlemail.com">PaLy</a>
 *
 * 
 */
public class JAXBReplySerializer<O> implements ReplySerializer<O> {

	private JAXBContext context = initJAXBContext();
	private JAXBReplyMapping<O> replyMapping = new JAXBReplyMapping<O>();
	
	private GenericObjectPool marshallerPool = new GenericObjectPool(new BasePoolableObjectFactory() {	
		public Object makeObject() throws Exception {
			return context.createMarshaller();
		}	
	});
	
	private GenericObjectPool unmarshallerPool = new GenericObjectPool(new BasePoolableObjectFactory() {
		
		public Object makeObject() throws Exception {
			return context.createUnmarshaller();
		}
	
	});
	
	
	public Reply<O> deserializeReply(InputStream inputStream) throws DeserializeException {
		try {
			Unmarshaller unmarshaller = (Unmarshaller) unmarshallerPool.borrowObject();
			try{
				org.lc.reply._1_0.Reply jaxbReply = (org.lc.reply._1_0.Reply) unmarshaller.unmarshal(inputStream);			
				return replyMapping.toReply(jaxbReply);
			}finally{
				unmarshallerPool.returnObject(unmarshaller);
			}
			
		} catch (Exception e) {
			throw new DeserializeException("Failed deserialize input-stream.", e);
		}
	}

	public void serializeReply(Reply<O> reply, OutputStream outputStream) throws SerializeException {
		try {
			Marshaller marshaller = (Marshaller) marshallerPool.borrowObject();
			try{
				org.lc.reply._1_0.Reply jaxbReply = replyMapping.toJAXBReply(reply);			
				marshaller.marshal(jaxbReply, outputStream);
			} finally{
				marshallerPool.returnObject(marshaller);
			}
		} catch (Exception e) {
			throw new SerializeException("Failed serialize reply.", e);
		}

	}
	

	
	private static JAXBContext initJAXBContext()  {
		try {
			return JAXBContext.newInstance(ObjectFactory.class.getPackage().getName(), ObjectFactory.class.getClassLoader());
		} catch (JAXBException e) {
			throw new RuntimeException(e);
		}
			
	}
	
	
	public void setContentMapper(ContentMapper contentMapper){
		replyMapping.setContentMapper(contentMapper);
	}

}

